package com.bawan.utils;

import com.bawan.model.ResponseModel;
import org.apache.commons.httpclient.*;
import org.apache.commons.httpclient.cookie.CookiePolicy;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.apache.commons.io.IOUtils;
import org.apache.log4j.Logger;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * Desc: HttpClient请求帮助类
 * User: ZhengCongChun
 * Date: 14-2-20
 * Time: 上午11:44
 *
 * @Version 1.0
 */
public class HttpClientHelper {
    private static Logger log = Logger.getLogger(HttpClientHelper.class);

    private static LinkedList<HttpClient> HttpClient_Cache = new LinkedList<HttpClient>();

    private static DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    private HttpClientHelper(){}

    private static final String charset_utf8 = "UTF-8";
    private static HttpClientHelper httpClientHelper = new HttpClientHelper();

    public static HttpClientHelper getInstance() {
        return httpClientHelper;
    }

    public ResponseModel post(String postUrl, Map params) {
        PostMethod postMethod = newPostMethod(postUrl, params);
        return request(postMethod);
    }

    private PostMethod newPostMethod(String postUrl, Map params) {
        PostMethod postMethod =  new PostMethod(postUrl);
        postMethod.getParams().setCookiePolicy(CookiePolicy.IGNORE_COOKIES);
        postMethod.addParameter("Content-Type", "application/x-www/form-urlencode; charset=UTF-8");
        addParamsToPostMethod(params, postMethod);
        return postMethod;
    }

    private void addParamsToPostMethod(Map params, PostMethod postMethod) {
        //Groovy代码
        /*params?.each { String key, value ->
            if (value == null) return

            if (value instanceof String) {
                postMethod.addParameter(key, value)
            } else if (value instanceof Date) {
                postMethod.addParameter(key, value?.format('yyyy-MM-dd HH:mm:ss'))
            } else {
                postMethod.addParameter(key, value.toString())
            }
        }
*/
        for(Iterator it = params.keySet().iterator(); it.hasNext();) {
            String key = it.next().toString();
            Object value = params.get(key);

            if (null == value) return;

            if (value instanceof String) {
                postMethod.addParameter(key, value.toString());
            } else if (value instanceof Date) {
                postMethod.addParameter(key, dateFormat.format(value));
            } else {
                postMethod.addParameter(key, value.toString());
            }
        }
    }

    public ResponseModel get(String url, Map params) {
        GetMethod getMethod = newGetMethod(url, params);
        return request(getMethod);
    }

    private GetMethod newGetMethod(String url, Map params) {
        GetMethod getMethod = new GetMethod(url);
        getMethod.getParams().setCookiePolicy(CookiePolicy.IGNORE_COOKIES);
        getMethod.getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET, charset_utf8);
        addParamsToGetMethod(params, getMethod);
        return getMethod;
    }

    private void addParamsToGetMethod(Map params, GetMethod getMethod) {
        List nameValuePairs = new ArrayList();

        //Groovy代码
        /*params?.each { key, value ->
            if (value == null) return

            if (value instanceof String) {
                nameValuePairs << new NameValuePair(key, value)
            } else if (value instanceof Date) {
                nameValuePairs << new NameValuePair(key, value?.format('yyyy-MM-dd HH:mm:ss'))
            } else {
                nameValuePairs << new NameValuePair(key, value?.toString())
            }
        }*/

        for(Iterator it = params.keySet().iterator(); it.hasNext();) {
            String key = it.next().toString();
            Object value = params.get(key);
            if (null == key) return;

            if (value instanceof String) {
                nameValuePairs.add(new NameValuePair(key, value.toString()));
            } else if (value instanceof Date) {
                nameValuePairs.add(new NameValuePair(key, ((Date) value).toLocaleString()));
            } else {
                nameValuePairs.add(new NameValuePair(key, value.toString()));
            }
        }

        if (nameValuePairs.size() > 0) {
            NameValuePair[] nameValuePairsArray = new NameValuePair[nameValuePairs.size()];
            for (int i = 0 ; i < nameValuePairs.size(); i ++) {
                nameValuePairsArray[i] = (NameValuePair)nameValuePairs.get(i);
            }
            getMethod.setQueryString(nameValuePairsArray);
        }
    }

    private ResponseModel request(HttpMethod httpMethod) {
        ResponseModel responseModel = new ResponseModel();
        HttpClient httpClient = this.getActiveHttpClient();

        long startTime = System.currentTimeMillis();
        try {
            int statusCode = httpClient.executeMethod(httpMethod);
            log.info("success to execute httpMethod[${httpMethod.getName()}],request url[${httpMethod.getURI()?.toString()}],response statusCode[${statusCode}]");
            responseModel.setStatusCode(statusCode);

            if (statusCode == HttpStatus.SC_OK) {
                responseModel.setSuccess(true);
            }

            responseModel.setResponseString(IOUtils.toString(httpMethod.getResponseBodyAsStream()));
        } catch (Exception e) {
            log.error("fail to execute httpMethod[${httpMethod.getName()}], url[${httpMethod.getURI()?.toString()}]", e);
        } finally {
            httpMethod.releaseConnection();
            this.releaseHttpClient(httpClient);
            if (log.isDebugEnabled()) {
                log.debug("执行http请求耗时：${System.currentTimeMillis() - startTime}");
            }
        }
        return responseModel;
    }

    private HttpClient getActiveHttpClient() {
        HttpClient httpClient = null;
        try {
            httpClient = HttpClient_Cache.removeFirst();

        } catch (Throwable e) {

            httpClient = this.newHttpClient();
            if (log.isDebugEnabled()) {
                log.debug("新建一个HTTPCLIENT实例,${httpClient?.hashCode()}");
            }
        }
        return httpClient;
    }

    private void releaseHttpClient(HttpClient httpClientInstance) {
        if (httpClientInstance != null) {
            HttpClient_Cache.addLast(httpClientInstance);
            if (log.isDebugEnabled()) {
                log.debug("释放一个HTTPCLIENT实例,${httpClientInstance?.hashCode()}");
            }
        }
    }

    private HttpClient newHttpClient() {
        HttpClient httpClient = new HttpClient(new MultiThreadedHttpConnectionManager());
        httpClient.getParams().setBooleanParameter("http.protocol.expect-continue", false);
        httpClient.getParams().setContentCharset(charset_utf8);

        HttpConnectionManagerParams managerParams = httpClient.getHttpConnectionManager().getParams();
        // 设置连接超时时间(单位毫秒)
        managerParams.setConnectionTimeout(5000);
        // 设置读数据超时时间(单位毫秒)
        managerParams.setSoTimeout(10000);

        return httpClient;
    }
}
